﻿using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;

namespace TestCstRatingConsole
{
    class StickerController
    {
        /// <summary>
        /// Sticker, all tree's data
        /// </summary>
        class StickerItem
        {
            public StickerItem()
            {
                //初始化一些为null的属性
                SignUpHistory = new List<DateTime>();
            }

            public string StickingName { get; set; }
            public string StickingDescription { get; set; }

            /// <summary>
            /// Max continual days in history
            /// </summary>
            public int HistoricMaxCotinueDays { get; private set; }

            public List<DateTime> SignUpHistory { get; private set; }

            private int m_continueDays;

            public int GetContinueDays(bool refreshDays = false)
            {
                if (refreshDays)
                {
                    var today = DateTime.Now.Date;
                    DateTime? histDate = GetLastSignDate();                          //Get last date

                    if (histDate != null)
                    {
                        //是昨天签到的，或者今天签到的，都可以试做连续签到，否则断开之：
                        if (!(today == histDate || histDate.Value.AddDays(1) == today))
                        {
                            m_continueDays = 0;
                        }
                    }
                }

                return m_continueDays;

            }

            public void AddContinueDays()
            {
                SetContinueDays(m_continueDays + 1);
            }

            public void SetContinueDays(int val)
            {
                if (val > HistoricMaxCotinueDays)
                {
                    HistoricMaxCotinueDays = val;
                }

                m_continueDays = val;
            }


            /// <summary>
            /// 是否可签到
            /// </summary>
            /// <param name="item"></param>
            /// <param name="lastD"></param>
            /// <returns></returns>
            public bool CanSign(out DateTime? lastD)
            {
                lastD = GetLastSignDate();
                if (lastD != null && lastD == DateTime.Now.Date)
                {
                    //Signed before, reject sign up again
                    return false;
                }
                else
                {
                    //Can sign:
                    return true;
                }
            }


            /// <summary>
            /// 是否可签到
            /// </summary>
            /// <param name="item"></param>
            /// <param name="lastD"></param>
            /// <returns></returns>
            public bool CanSign()
            {
                DateTime? d;
                return CanSign(out d);
            }

            /// <summary>
            /// 获得最近的一个签到日期（年月日）
            /// </summary>
            /// <returns></returns>
            public DateTime? GetLastSignDate()
            {
                if (IsNullOrEmptyList(SignUpHistory))
                {
                    return null;
                }
                else
                {
                    return SignUpHistory[SignUpHistory.Count - 1].Date;
                }
            }

        }

        /// <summary>
        /// For each beautiful tree:
        /// </summary>
        public class TreeItem
        {
            /// <summary>
            /// Is something memorable happen? Write it down:
            /// </summary>
            public string DailyEvent { get; set; }

            public DateTime PlantTime { get; set; }

            public int GrowthPoints { get; private set; }

            const float C_MinSize = 0.5f;
            const float C_MaxSize = 2f;
            public float Size
            {
                get
                {
                    int growth = GrowthPoints;
                    if (growth <= 0)
                    {
                        growth = 1;
                    }
#if UNITY
                    float size = Mathf.Log((float)GrowthPoints, 16);
#else
                    float size = (float)Math.Log((float)GrowthPoints, 16);
#endif
                    if (size <= 0.1f)
                    {
                        size = 0.1f;//最小大小：
                    }
                    return size;
                }
            }

            public void Grow()
            {
                var currDate = DateTime.Now;
                var delta = currDate - PlantTime;

                //取日期差
                GrowthPoints = delta.Days;
            }
        }

        public enum SignUpResult { NoJobFound, SignedAlready, Sucess }

        /// <summary>
        /// Those with parents:
        /// </summary>
        Dictionary<string, StickerItem> m_dictStickerItems = new Dictionary<string, StickerItem>();

        //TODO -- daily sticker
        /// <summary>
        /// Those don't have any parents. 
        /// You can use it for daily.
        /// You can have 5 memo per days.
        /// </summary>
        List<StickerItem> m_sparkStickerItems;

        /// <summary>
        /// 连续N天即可获得奖励
        /// </summary>
        int m_rewardDays = 10;

        /// <summary>
        /// 多少种类的Sticker
        /// </summary>
        int m_maxStickerTypesCount = 5;

        /// <summary>
        /// 创建一个事项
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="description"></param>
        /// <returns></returns>
        public bool CreateJob(string jobName, string description)
        {
            if (m_dictStickerItems.Count > m_maxStickerTypesCount)
            {
                //up to max:
                return false;
            }
            else if (!m_dictStickerItems.ContainsKey(jobName))
            {
                var item = new StickerItem();
                item.StickingName = jobName;
                item.StickingDescription = description;
                item.SetContinueDays(0);

                m_dictStickerItems.Add(jobName, item);
                return true;
            }
            else //already exist:
            {
                return false;
            }
        }

        /// <summary>
        /// For asking : have you done xxx yet?
        /// </summary>
        /// <returns></returns>
        public List<string> GetToDoJobs()
        {
            var askList = new List<string>();
            foreach (var item in m_dictStickerItems)
            {
                if (item.Value.CanSign())
                {
                    askList.Add(item.Key);
                }

            }

            return askList;
        }

        /// <summary>
        /// Sign up for the sticker
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public SignUpResult SignUp(string jobName)
        {
            if (m_dictStickerItems.ContainsKey(jobName))
            {
                var item = m_dictStickerItems[jobName];

                DateTime? lastDate;
                if (item.CanSign(out lastDate))
                {
                    //Has continue signed up:
                    if (lastDate.HasValue && lastDate.Value.AddDays(1) == DateTime.Now.Date)
                    {
                        //Is continual signing:
                        item.AddContinueDays();

                        //If continueDays up to %10, reward:
                        if (item.GetContinueDays() % m_rewardDays == 0)
                        {
                            DoReward();
                        }
                    }
                    else
                    {
                        //ContinueDays break down:
                        item.SetContinueDays(1);
                    }

                    item.SignUpHistory.Add(DateTime.Now);
                    return SignUpResult.Sucess;
                }
                else
                {
                    return SignUpResult.SignedAlready;
                }


            }
            else
            {
                return SignUpResult.NoJobFound;
            }
        }


        /// <summary>
        /// 测试用：将所有历史往前移动1天：
        /// </summary>
        public void Test_MoveBackDays(string job)
        {
            if (m_dictStickerItems.ContainsKey(job))
            {
                var sticker = m_dictStickerItems[job];

                for (int i = 0; i < sticker.SignUpHistory.Count; i++)
                {
                    //值类型，重新减1再赋值回去：
                    sticker.SignUpHistory[i] = sticker.SignUpHistory[i].AddDays(-1);
                }
            }
        }

        public string Test_GetHis(string job)
        {
            StringBuilder sb = new StringBuilder();
            if (m_dictStickerItems.ContainsKey(job))
            {
                var sticker = m_dictStickerItems[job];
                if (sticker.SignUpHistory.Count > 0)
                {
                    foreach (var history in sticker.SignUpHistory)
                    {
                        sb.AppendFormat("{0} \n", history.ToString("yyyy-MM-dd"));
                    }
                }
                sb.AppendFormat("Stick on {1} for [{0}] days. \n", sticker.GetContinueDays(true), sticker.StickingName);
            }

            return sb.ToString();
        }

        public void Test_GetNoSignJobs()
        {
            List<string> jobsToDo = GetToDoJobs();
            foreach (var str in jobsToDo)
            {
                Console.WriteLine("You can sign: [{0}]", str);
            }
        }

        public void Test_Save(string dataFilePath)
        {
            string saveJson = Serialized();
            System.IO.File.WriteAllText(dataFilePath, saveJson);
        }

        internal void Test_Read(string dataFilePath)
        {
            string readJson = System.IO.File.ReadAllText(dataFilePath);
            Deserialized(readJson);
        }

        void DoReward()
        {

        }


        /// <summary>
        /// 判断该List为null或长度为0
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool IsNullOrEmptyList<T>(ICollection<T> list)
        {
            return (list == null || list.Count == 0);
        }

        /// <summary>
        /// 序列化所有StickItem
        /// </summary>
        /// <returns></returns>
        public string Serialized()
        {
            return JsonConvert.SerializeObject(m_dictStickerItems);
        }

        /// <summary>
        /// 反序列化所有StickItem
        /// </summary>
        /// <param name="json"></param>
        public void Deserialized(string json)
        {
            m_dictStickerItems = JsonConvert.DeserializeObject<Dictionary<string, StickerItem>>(json);
        }



    }
}
